package wangwenjun.phase1.flightquery;

import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import util.ThreadUtil;
import wangwenjun.phase1.flightquery.join.FlightQueryJoinTask;
import wangwenjun.phase1.flightquery.latch.v1.CountDownLatchV1;
import wangwenjun.phase1.flightquery.latch.v1.FlightQueryLatchTaskV1;
import wangwenjun.phase1.flightquery.latch.v1.LatchV1;
import wangwenjun.phase1.flightquery.latch.v2.CountDownLatchV2;
import wangwenjun.phase1.flightquery.latch.v2.FlightQueryLatchTaskV2;
import wangwenjun.phase1.flightquery.latch.v2.LatchV2;
import wangwenjun.phase1.flightquery.latch.v2.LatchWaitTimeoutException;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import static java.util.stream.Collectors.toList;

/**
 * @author ChangLiang
 * @date 2020/6/16
 */
@Slf4j
public class AppTest {

    private static List<String> flightCompany = Arrays.asList(
            "CSA", "CEA", "HNA"
    );

    private String origin;

    private String dest;

    @BeforeEach
    public void setUp() {
        this.origin = "SH";
        this.dest = "BJ";
    }

    @Test
    @DisplayName("test join")
    public void test(){
        final List<String> result = new ArrayList<>();
        // 创建了多个任务
        List<FlightQueryJoinTask> tasks = flightCompany.stream().map(f -> new FlightQueryJoinTask(f, origin, dest)).collect(toList());
        executeTasks(result, tasks);
        log.info("result:{}",result);
    }

    private void executeTasks(List<String> result, List<FlightQueryJoinTask> tasks) {
        // 对应启动了多个线程 执行多个任务
        tasks.forEach(Thread::start);
        tasks.forEach(t->{
            try {
                // main线程主动调用t.join，main线程进入block状态
                t.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        // 在此之前 当前线程会waiting住 获取每一个查询的结果 加入到result中
        tasks.stream().map(FlightQueryJoinTask::get).forEach(result::addAll);
    }

    @Test
    @DisplayName("test CountDownLatchV1 wait forever")
    public void test2() throws InterruptedException {
        LatchV1 latch = new CountDownLatchV1(flightCompany.size());

        final List<String> result = new ArrayList<>();
        List<FlightQueryLatchTaskV1> tasks = flightCompany.stream().map(f -> new FlightQueryLatchTaskV1(f, latch, origin, dest)).collect(Collectors.toList());
        tasks.forEach(Thread::start);
        latch.await();
        tasks.stream().map(FlightQueryLatchTaskV1::get).forEach(result::addAll);
        log.info("result:{}",result);
    }

    @Test
    @DisplayName("test CountDownLatchV1 wait with timeout")
    public void test3() throws InterruptedException {
        LatchV2 latch = new CountDownLatchV2(flightCompany.size());

        final List<String> result = new ArrayList<>();
        List<FlightQueryLatchTaskV2> tasks = flightCompany.stream().map(f -> new FlightQueryLatchTaskV2(f, latch, origin, dest)).collect(Collectors.toList());
        tasks.forEach(Thread::start);
        try {
            latch.await(TimeUnit.SECONDS,3);
        } catch (LatchWaitTimeoutException e) {
            log.error(ThreadUtil.exceptionToString(e));
        }
        tasks.stream().map(FlightQueryLatchTaskV2::get).forEach(result::addAll);
        log.info("result:{}",result);
        Thread.currentThread().join();
    }


    @Test
    @DisplayName("test CountDownLatchV1 wait with timeout and callback")
    public void test4() throws InterruptedException {
        final List<String> result = new ArrayList<>();
        LatchV2 latch = new CountDownLatchV2(flightCompany.size(),() -> log.info("result:{}", result));

        List<FlightQueryLatchTaskV2> tasks = flightCompany.stream().map(f -> new FlightQueryLatchTaskV2(f, latch, origin, dest)).collect(Collectors.toList());
        tasks.forEach(Thread::start);
        try {
            latch.await(TimeUnit.SECONDS,3);
        } catch (LatchWaitTimeoutException e) {
            log.error(ThreadUtil.exceptionToString(e));
        }
        tasks.stream().map(FlightQueryLatchTaskV2::get).forEach(result::addAll);
        // 这里的Runnable由于没有使用#start 所以只是一个普通的匿名内部类进行普通run方法的执行
        // wangwenjun.phase1.flightquery.AppTest$$Lambda$147/1671507048@16610890
        System.out.println(latch.getRunnable());
        latch.getRunnable().run();
        Thread.currentThread().join();
    }



}
